/* -*- mode: c++ -*-
**
** topp.cpp
**
** top level instatiations and simulation control
** 
** Made by Kjetil Svarstad
** 
*/


#include <systemc.h>

#include "if.h"
#include "button.h"
#include "control.h"
#include <iostream>

// The Bus system
class Bus : public sc_channel,
						public controlBusIf,
						public buttonBusIf
{
	private:
	sc_mutex busMutex;
	int currentButton;
	int numberOfButtons;
	static const int size = 10;
	
	
	public:
		sc_port < controlIf> controlp;
		sc_port < buttonIf, 0> buttonp;
	
		Bus (sc_module_name name) : sc_channel (name) 
		{
			
		}
		void buttonPushed(int buttonNumber)
		{// When a button is pushed, the number is sent to ctrl which
		 // determines if light should be on or off. Only one button can
		 // access the bus at once to avoid race conditions.
		 
		 busMutex.lock(); // This should wait if bus is occupied.
		 printf("\n");
		 currentButton = buttonNumber;
		 controlp->buttonPushed(buttonNumber);
		}
		
		void switchLight(bool b)
		{ // Response from control wether or not to switch on the light.
			// If b == 1, turn on light at currentButton.
			if(b)
			{
				buttonp[currentButton]->switchLight(true);
			}
			
			else 
			{ // If b == 0, turn off all the lights.
				for(int i = 1;i<size;i++)
				{
					buttonp[i]->switchLight(false);
				}
			}
			busMutex.unlock();
		}
};

class top : public sc_module 
{
	public:
  Button * iButtons[10]; // 10 pointers
  Bus * iBus;           // single pointer
  Control * iControl;   // single pointer

  top (sc_module_name name) : sc_module (name) 
  {
    // Creating instances
    iBus = new Bus ("Bus");
    
    // Creating buttons and connecting to bus.
    // Need a char buffer to create unique instance names in:
    char buf[20];
    for (int i = 0; i <= 9; i++) 
    {
      // Create unique name
      sprintf (buf, "Button%d\0", i);
      // Create specific Button instance
      iButtons[i] = new Button (buf, i);
      // and then connect it, the '*' dereferences the button pointer!
      iBus->buttonp(*(iButtons[i]));
      iButtons[i]->busp (*iBus);
    }
    
    // Create control and connect to the bus.
    iControl = new Control("Control");
    iControl->busp(*iBus);
    iBus->controlp(*iControl);
    
    SC_HAS_PROCESS(top);
    SC_THREAD(main);
  }
  void main(void)
  {
		// Push correct sequence of buttons
		/*
		int correctSequence[9] = {3,8,1,2,9,5,7,6,4};
		for(int i=0;i<=8;i++)
		{
			wait(1,SC_NS);
			iButtons[correctSequence[i]]->PUSH.write(true);
			wait(1,SC_NS);
			iButtons[correctSequence[i]]->PUSH.write(false);
		}
		*/
		// Push incorrect sequence of buttons
		int incorrectSequence[11] = {1,2,3,4,5,3,4,6,3,4,9};
		for(int i=0;i<=10;i++)
		{
			wait(1,SC_NS);
			iButtons[incorrectSequence[i]]->PUSH.write(true);
			wait(1,SC_NS);
			iButtons[incorrectSequence[i]]->PUSH.write(false);
		}
    
		sc_stop();
		
	}
};


int sc_main (int argc , char *argv[])  {
  // instantiate top
	top iTop("Top");
  // tracing of signals
  char temp[20];
  sc_trace_file* tracefile;
  tracefile = sc_create_vcd_trace_file("oving2trace");
  for(int i = 0; i<=9;i++)
  {
		sprintf(temp, "Button%i_push\0",i);
		sc_trace(tracefile,iTop.iButtons[i]->PUSH,temp);
		sprintf(temp, "Button%i_light\0",i);
		sc_trace(tracefile,iTop.iButtons[i]->light,temp);
	}
  sc_start (); 
  return 0;
}



